#include <pthread.h>
#include <sys/mutexqueue.h>
#include <sys/proc.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include<sys/mutexqueue.h>
#include <sys/time.h>

static pthread_condattr_t __pthread_cond_default_attr = PTHREAD_COND_ATTR_INITIALIZER
;

int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr)
{
    if (!cond)
        return EINVAL;

    if (cond_attr)
    {
        memcpy(&cond->cond_attr, cond_attr, sizeof(pthread_mutexattr_t));
    }
    else
    {
        cond->cond_attr = __pthread_cond_default_attr;
    }
    pthread_spin_init(&cond->spin, PTHREAD_PROCESS_PRIVATE);
    //wait queue
    cond->mutex_queue = mutex_queue_alloc();
    if (!cond->mutex_queue)
        return ENOMEM;
    return 0;
}

int pthread_cond_destroy(pthread_cond_t *cond)
{
    if (!cond)
        return EINVAL;
    if (cond->mutex_queue >= 0)
        mutex_queue_free(cond->mutex_queue);
    cond->mutex_queue = -1;
    return 0;
}

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
    if (!cond || !mutex)
        return EINVAL;
    if (cond->mutex_queue < 0)
    {
        cond->mutex_queue = mutex_queue_alloc();
        if (cond->mutex_queue < 0)
            return ENOMEM;
    }
    pthread_spin_lock(&cond->spin);
    pthread_mutex_unlock(mutex);
    mutex_queue_wait(cond->mutex_queue, &cond->spin.count, MUTEX_QUEUE_ZERO, 0);
    pthread_mutex_lock(mutex);
    return 0;
}

int pthread_cond_timeout(pthread_cond_t *cond, pthread_mutex_t *mutex, const timespec_t *abstime)
{
    if (!cond || !mutex)
        return EINVAL;
    if (cond->mutex_queue < 0)
    {
        cond->mutex_queue = mutex_queue_alloc();
        if (cond->mutex_queue < 0)
            return ENOMEM;
    }
    int retval = 0;
    pthread_spin_lock(&cond->spin);
    pthread_mutex_unlock(mutex);
    retval = mutex_queue_wait(cond->mutex_queue, &cond->spin.count, MUTEX_QUEUE_TIMED | MUTEX_QUEUE_ZERO, 0);
    pthread_mutex_lock(mutex);



    return 0;
}

int pthread_cond_signal(pthread_cond_t *cond)
{
    if (!cond)
        return EINVAL;
    if (cond->mutex_queue < 0)
    {
        cond->mutex_queue = mutex_queue_alloc();
        if (cond->mutex_queue < 0)
            return ENOMEM;
    }

    pthread_spin_lock(&cond->spin);
    mutex_queue_wake(cond->mutex_queue, NULL, 0, 0);
    pthread_spin_unlock(&cond->spin);
    return 0;
}

int pthread_cond_broadcast(pthread_cond_t *cond)
{
    if (!cond)
        return EINVAL;
    if (cond->mutex_queue < 0)
    {
        cond->mutex_queue = mutex_queue_alloc();
        if (cond->mutex_queue < 0)
            return ENOMEM;
    }

    pthread_spin_lock(&cond->spin);
    mutex_queue_wake(cond->mutex_queue, NULL, MUTEX_QUEUE_ALL, 0);
    pthread_spin_unlock(&cond->spin);

    return 0;
}

int pthread_condattr_init(pthread_condattr_t *attr)
{
    if (!attr)
        return EINVAL;
    *attr = (pthread_condattr_t)PTHREAD_COND_ATTR_INITIALIZER;
    return 0;
}

int pthread_condattr_destroy(pthread_condattr_t *attr)
{
    if (!attr)
        return EINVAL;
    attr->pshared = 0;
    return 0;
}

int pthread_condattr_getpshared(pthread_condattr_t *attr, int *pshared)
{
    if (!attr || !pshared)
        return EINVAL;
    if (pshared)
        *pshared = attr->pshared;
    return 0;
}

int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared)
{
    if (!attr)
        return EINVAL;
    attr->pshared = pshared;
    return 0;
}
